using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Data;
using System.Data.Common;
using System.ComponentModel;

namespace Tilver.DBConnectionUI
{
    internal abstract class UDLStringBuilder
    {
        Dictionary<string, string> aliases;
        Dictionary<string, string> overrides;
        public UDLStringBuilder()
        {
            aliases = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
            overrides = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
        }

        [Browsable(false)]
        public string ConnectionString
        {
            get { return BuildConnectionString(); }
            set { ParseConnectionString(value); }
        }

        protected virtual string BuildConnectionString()
        {
            StringBuilder sb = new StringBuilder();
            PropertyDescriptorCollection props = TypeDescriptor.GetProperties(this);
            foreach (PropertyDescriptor pd in props)
            {
                if (pd.Name == "ConnectionString")
                    continue;

                object val = pd.GetValue(this);
                object def = DefaultValue(pd);

                if (val != null && !val.Equals(def))
                {
                    if (sb.Length > 0)
                        sb.Append("; ");
                    if(!overrides.ContainsKey(pd.DisplayName))
                        sb.Append(pd.DisplayName + "=" + val.ToString());
                    else
                        sb.Append(overrides[pd.DisplayName] + "=" + val.ToString());
                }
            }
            return sb.ToString();
        }
        protected virtual void ParseConnectionString(string connString)
        {
            string[] pairs = connString.Split(';');
            foreach (string pair in pairs)
            {
                string[] tokens = pair.Split('=');
                if (tokens.Length == 2)
                {
                    string key = tokens[0].Trim();
                    string val = tokens[1].Trim();
                    if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(val))
                    {
                        PropertyDescriptor pd = FindProperty(key);
                        if (null == pd)
                        {
                            if(aliases.ContainsKey(key))
                                this.SetValue(aliases[key], val);
                        }
                        else
                            this.SetValue(key, val);
                    }
                }
            }
        }

        public void RegisterAlias(string aliasName, string primaryName)
        {
            if (aliases.ContainsKey(aliasName))
                throw new InvalidOperationException("Duplicate alias name");
            aliases.Add(aliasName, primaryName);
        }
        public void AddKeywordOverride(string propName, string overrideName)
        {
            if (!overrides.ContainsKey(propName))
                overrides.Add(propName, overrideName);
        }
        public object GetValue(string propName)
        {
            PropertyDescriptor prop = this.FindProperty(propName);
            if (prop != null)
            {
                object val = prop.GetValue(this);
                if (val != null)
                    return val;
            }
            return null;
        }
        public void SetValue(string propName, object value)
        {
            PropertyDescriptor prop = this.FindProperty(propName);
            if (prop != null)
            {
                Type toType = prop.PropertyType;
                try
                {
                    if (toType == typeof(Boolean))
                        prop.SetValue(this, Convert.ToBoolean(value));
                    else if (toType == typeof(Int32))
                        prop.SetValue(this, Convert.ToInt32(value));
                    else
                    {
                        prop.SetValue(this, value);
                    }
                }
                catch (Exception) { }
            }
        }
        private object DefaultValue(PropertyDescriptor pd)
        {
            foreach (Attribute att in pd.Attributes)
            {
                if (att is DefaultValueAttribute)
                    return ((DefaultValueAttribute)att).Value;
            }
            return null;
        }
        private PropertyDescriptor FindProperty(string propName)
        {
            // searches for the display name first
            foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(this))
            {
                if (prop.DisplayName.Equals(propName, StringComparison.OrdinalIgnoreCase))
                    return prop;
            }

            //if not found it searches for the name
            foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(this))
            {
                if (prop.Name.Equals(propName, StringComparison.OrdinalIgnoreCase))
                    return prop;
            }
            return null;
        }

    }
}
